今日已更新 184 条资讯 | 累计 37433 条内容
关于我们

标签:#Git

找到 1710 篇相关文章

AI 资讯

Why French Sound Inventories Differ — and How We Published a Bounded 35-Sound Learning Dataset

When a language-learning product says it teaches “the sounds of French,” one deceptively simple question appears immediately: how many sounds are there? There is no useful answer without first defining the job the inventory is meant to do. A phonological analysis, a pronunciation dictionary, a speech-recognition system, and a beginner curriculum can all model French sound structure differently without one of them necessarily being careless. They have different users, evidence, and failure costs. Our team encountered this while turning Parle's internal pronunciation inventory into a public CSV. We needed a list that could connect IPA symbols to French spelling patterns, example words, and short mouth cues for English-speaking beginners. We also needed to avoid presenting one product's learning model as the only correct account of French phonology. The result is a bounded dataset of 35 practical sound entries. This article explains the design decisions, the schema, and the limits we published with it. A teaching inventory is a model, not a census The International Phonetic Alphabet gives us a shared notation for describing speech sounds. It does not require every analyst or teacher to draw identical category boundaries for every language variety. The official IPA chart is a notation system; selecting a French inventory still requires linguistic and pedagogical decisions. Counts can change when an inventory treats any of the following differently: a contrast that is maintained by some speakers but merged by others; a marginal or loan sound that appears mainly in borrowed words; schwa, whose realization and deletion depend heavily on context and variety; a historical contrast that remains visible in spelling but not in every speaker's production; a phonetic realization versus a contrastive phoneme; a glide represented separately from its related vowel. For a curriculum, the important question is not “What number wins?” It is “What distinctions and cues help this audienc

2026-08-14 原文 →
AI 资讯

A static site that collects form submissions, in one HTML attribute

A static site has no backend. That is the point of one — and it is also why the contact form is the first thing that breaks. The usual answers are a third-party form service with its own signup, a serverless function you now maintain, or a mailto: link nobody clicks. There is a third option that falls out of how static hosting already works: the host is in the path of every HTML response it serves. It can collect the form itself. On harvis.dev that is one attribute: <form harvis-form= "contact" > <input name= "email" type= "email" required > <textarea name= "message" ></textarea> <button> Send </button> </form> Deploy, and submissions show up in the dashboard. No script tag, no API key in the page, no fetch() , no JavaScript at all — the form works with JS disabled, because it is a plain HTML form doing what plain HTML forms have always done. The page I am describing is live at harvis-forms-example.harvis.dev — submit the form and see where you land. Everything below is what makes that page work. What actually happens The rewrite happens on the way out, while the HTML is being served: action and method are replaced with /__harvis/form/contact on your site's own subdomain. Same origin, so there is no CORS, no preflight, and nothing in the page has to know a project id. A honeypot field is inserted. It is positioned off-screen rather than display: none , because a bot that skips hidden inputs is a bot that would otherwise get through. Anything that fills it in gets the success page and is stored nowhere — a bot that can tell it was caught is a bot that tries again differently. data-harvis-redirect="/thanks.html" becomes a hidden field, since the handler never sees your HTML — only what the browser posts. It is re-validated on arrival, and a protocol-relative //somewhere-else is refused. The reply is a 303 , so the browser follows it with a GET and a refresh on the thank-you page cannot post the form twice. The form name is part of a URL and a dashboard heading, so it

2026-08-13 原文 →
AI 资讯

Running the same SQL checks in a browser, CLI and pull request

I wanted one set of SQL checks to work in three places: while exploring a query, from a terminal and during code review. That became SQL Atlas. It is a local, deterministic SQL analyzer with a browser interface, a CLI and a GitHub Action. This article covers the interfaces, the CI contract and the limits of static SQL analysis. One analyzer, three interfaces The analyzer returns structured data instead of printing messages directly. Each interface decides how to present the same result: The browser explains findings and links them to learning material. The CLI returns text, JSON or Markdown and uses stable exit codes. The GitHub Action converts findings into file annotations and a job summary. Keeping presentation outside the analyzer prevents the CLI and Action from becoming separate implementations with different behavior. A CLI needs a contract The CLI accepts one or more files, or SQL through standard input: npx --yes sql-atlas@0.5.1 analyze query.sql echo "SELECT * FROM customers;" | npx --yes sql-atlas@0.5.1 analyze - It supports PostgreSQL, MySQL, Oracle, SQLite, SQL Server and a generic mode. Output can be text for a person, JSON for another program or Markdown for an issue or report. Exit codes are part of the interface: 0 means analysis completed and the configured policy passed. 1 means analysis completed but a severity or score threshold failed. 2 means the command or input was invalid. This distinction matters in CI. A policy failure is not the same as a broken invocation. Turning findings into pull request feedback The Action runs as a bundled Node 24 program and does not download dependencies at runtime. A minimal workflow looks like this: name : SQL review on : pull_request : paths : - " **/*.sql" permissions : contents : read jobs : sql-atlas : runs-on : ubuntu-latest steps : - uses : actions/checkout@v7 - uses : milekv/sql-atlas@v0.5.1 with : paths : | migrations/**/*.sql schema/**/*.sql dialect : postgresql fail-on : critical min-score : 60 Findin

2026-08-13 原文 →
AI 资讯

# 🚀 I Built a Jenkins CI/CD Pipeline From Scratch — Here's Every Bug I Hit (and How I Fixed Them)

A learning-in-public story about Flask, Jenkins, AWS EC2, systemd, and finally shipping a live demo on Vercel. 🎯 TL;DR I built PyPulse, a tiny Flask app, and wired it up to a full CI/CD pipeline: push to GitHub → Jenkins builds → tests → deploys to AWS EC2 → auto-triggered via webhook → managed by systemd. Along the way I broke almost every piece of it at least once, and fixed each one. I also deployed a permanent live demo on Vercel, since my EC2 instance is running on the AWS free trial and won't live forever. 🔗 Live demo: pypulse-pi.vercel.app 🔗 Live demo (health check): pypulse-pi.vercel.app/health If you're learning DevOps and want to see what the real, messy version of "just set up a CI/CD pipeline" looks like — not the polished tutorial version — this is that. 🧰 The Stack Piece Tool Job App Flask + pytest + gunicorn The actual web app and its tests CI/CD Jenkins (on EC2, Ubuntu 22.04) Build → Test → Deploy automation Source control GitHub Single source of truth Trigger GitHub Webhook Auto-runs the pipeline on every push Process management systemd Keeps the app alive on reboot/crash Permanent demo Vercel Live URL that survives EC2 termination 🏗️ The App: PyPulse Nothing fancy on purpose — the whole point of this project was the pipeline, not the app. python app.py from flask import Flask, jsonify from datetime import datetime, timezone app = Flask( name ) @app.route("/") def home(): return jsonify({ "message": "Hello from PyPulse", "time": datetime.now(timezone.utc).isoformat() }) @app.route("/health") def health(): return jsonify({"status": "ok"}), 200 if name == " main ": app.run(host="0.0.0.0", port=5000) Two routes. Two tests. That's it. Small enough that when something broke, I knew it wasn't the app — it was the plumbing around it. That turned out to be the right call, because the plumbing broke a lot. 😅 ⚙️ The Pipeline: Build → Test → Deploy Here's the mental model I ended up with for a Jenkinsfile: Each stage is a gate. If Build fails, Test never runs.

2026-08-13 原文 →
AI 资讯

GitLab CE Comes Without a Runner: Why Nothing Executes Your Pipelines

You installed GitLab Community Edition, pushed a .gitlab-ci.yml , and watched the pipeline sit at pending until it went grey. No error, no failed job, nothing in the logs worth reading. Nothing is broken. Your instance has no runners, and it never had any. Why a fresh instance has none GitLab is two things that people assume are one thing. There is the application: repositories, issues, merge requests, the CI/CD system that reads your .gitlab-ci.yml and builds a pipeline out of it. And there is GitLab Runner: a separate program, on a separate machine, that actually executes jobs. The Omnibus package installs the first. It does not install the second, and it does not come with any machines to run it on. The confusion comes from GitLab.com, where shared runners are switched on by default and most people's first experience of CI is that it simply works. That shared fleet is hardware GitLab owns and operates as part of their hosted service. It is not part of the software you downloaded, so it does not come across when you run your own instance. So on a self-managed install, GitLab will happily accept your pipeline definition, parse it, create the jobs, and queue them. Then it waits for a runner to ask for work. If no runner ever asks, the jobs wait indefinitely. Confirming it in thirty seconds Go to Admin Area → CI/CD → Runners on your instance. If the list is empty, that is your answer. For a single project, Settings → CI/CD → Runners shows the same thing scoped narrower. A fresh instance shows nothing in either place. From the command line on the GitLab server: sudo gitlab-rails runner "puts Ci::Runner.count" If that prints 0 , no runner has ever been registered against this instance. One thing worth ruling out at the same time: a job can also sit pending when runners do exist but none of them match the job's tags. If your runner list is not empty, check whether your jobs specify tags: that no runner carries. That is a different problem with a different fix, and it is

2026-08-13 原文 →