Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

Needs DirXMLDev 0.57.0.

### Fixed

- Importing a Designer project that holds two objects of one name (a driver set using Libraries in
two containers, or a package upgrade's leftover) no longer gives a project where nearly every
page fails with `duplicate artifact path` (#174). The import keeps one, and the page now waits
on the result, saying which one it kept and what was left out, until you open the workbench. The
first commit's message records it too. A project imported before this loads again, and
validation names the duplicate.

### Changed

- "An internal error" says where the server log is (`docker logs idmweb`, or the terminal that
runs the server); the quickstart's *Day to day* says so too.

## [0.80.0] - 2026-10-27

Needs DirXMLDev 0.56.0.
Expand Down
22 changes: 22 additions & 0 deletions bin/smoke-hosted.sh
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,28 @@ try:
check("adding a project to a server set up with the old repo.* keys keeps its first project", s == 200 and "projects=repo,extra" in conf1 and "project.repo.repo.url=" in conf1 and "repo.url=" not in conf1.replace("project.repo.repo.url=", "").replace("project.extra.repo.url=", ""))
s, r, _ = bob.call("POST", "/api/setup/directory", {"project": "outside", "path": "/etc"})
check("a deployer may attach only under setup.roots (#41)", s == 400 and "outside" in r.get("error", ""))
# #174: a Designer project whose driver set uses two Libraries that both hold "es-shared"
proj = os.path.join(work, "two-libraries"); orph = os.path.join(proj, "Model", "EdirOrphan"); os.makedirs(os.path.join(orph, "L2"))
def cobj(name, typ, inner):
return ('<?xml version="1.0" encoding="utf-8"?><com.novell.designer.model:CObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
'xmlns:com.novell.designer.model="http://com.novell.designer.model" name="%s" type="%s">%s</com.novell.designer.model:CObject>' % (name, typ, inner))
def cstr(n, v): return '<attributes xsi:type="com.novell.designer.model:CString" attrName="%s" value="%s"/>' % (n, v)
def rel(n, k): return '<relations name="%s" type="Child" key="#%s"/>' % (n, k)
files = {
"DS.DriverSet_": cobj("DS", "DriverSet", cstr("DSetContext", "o=system") + rel("Idm:Libraries", "L2.Library_") + rel("Idm:Libraries", "L1.Library_")),
"L1.Library_": cobj("Library", "Library", cstr("LibraryContext", "cn=DS,o=system") + rel("Idm:Resources", "J1.ECMAScriptResource_")),
"L2.Library_": cobj("Library", "Library", cstr("LibraryContext", "ou=shared,o=system") + rel("Idm:Resources", "J2.ECMAScriptResource_")),
"L2/J1.ECMAScriptResource_": cobj("es-shared", "ECMAScriptResource", cstr("DirXML-ContentType", "text/ecmascript")),
"L2/J1_contents.xml": "function own(){}",
"L2/J2.ECMAScriptResource_": cobj("es-shared", "ECMAScriptResource", cstr("DirXML-ContentType", "text/ecmascript")),
"L2/J2_contents.xml": "function shared(){}",
}
for f, t in files.items():
open(os.path.join(orph, f), "w").write(t)
open(os.path.join(proj, ".project"), "w").write("<projectDescription><name>two-libraries</name></projectDescription>")
s, r, _ = bob.call("POST", "/api/setup/project", {"project": "twolib", "path": proj})
check("#174: a project with an object two Libraries hold imports, and the page is told which it kept", s == 200
and any("kept the resource (in cn=Library,cn=DS,o=system" in n and "one Library" in n for n in r.get("notes", [])))
# #42: the audit log, deployers only
import datetime
def when(t): # 3, 6 or 9 fraction digits: compare as times, not text (#161)
Expand Down
2 changes: 2 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ command there (`docker exec idmweb idm vault.status --env lab`) binds as you do
- **Stop:** `docker compose -f "$HOME/idmweb/compose.yml" down`. Everything lives in the folder:
back it up, move it or delete it, and that is the whole install.
- **One per machine:** the container is named `idmweb`.
- **The server log:** `docker logs idmweb` (add `--tail 200` for the end). When the page reports
"an internal error", the stack trace is there; attach it to an issue.
- **Moving to a server for a team:** [hosted-install.md](hosted-install.md) is the same image
behind a proxy with TLS and your identity provider. Push the folder's `repo.git` to GitHub or
GitLab and point the server's project at it.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<!-- The DirXMLDev release this server is written against. Install it once with
`mvn -o install -DskipTests` in the DirXMLDev checkout; bin/idmweb then runs
against that checkout's classes, engine jars and simulator. -->
<dirxmldev.version>0.56.0</dirxmldev.version>
<dirxmldev.version>0.57.0</dirxmldev.version>
<simulator.version>1.7.0</simulator.version>
<!-- the DirXML Trace Viewer's library: parser, highlighter, LDAP trace source (its release attaches the jar) -->
<!-- Directory Console's shared libraries (console-auth: OIDC sign-in, TLS trust). Install with
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/pointblue/dirxml/web/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ public void handle(HttpExchange ex) throws IOException {
// the page says where to find it
System.err.println("error: " + ex.getRequestMethod() + " " + ex.getRequestURI().getPath() + ": " + e);
e.printStackTrace();
send(ex, 500, error(e.getClass().getSimpleName() + ": " + e.getMessage() + " (an internal error; the server log has the details)"));
send(ex, 500, error(e.getClass().getSimpleName() + ": " + e.getMessage() + " (an internal error; the server log has the details: docker logs idmweb, or the terminal that runs the server)"));
return;
}
send(ex, 500, error(e.getClass().getSimpleName() + ": " + e.getMessage()));
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/pointblue/dirxml/web/SetupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ public Map<String, Object> fromVault(Session session, String projectName, String
}
}
Map<String, Object> m = seedRepository(name, live, "Imported from " + envName + " (" + dn + ")");
@SuppressWarnings("unchecked")
List<String> leftOut = (List<String>) m.getOrDefault("notes", List.of());
notes.addAll(leftOut);
m.put("notes", notes);
m.put("driverSet", dn);
done(session, "vault", Map.of("project", name, "env", envName, "driverSet", dn, "drivers", live.drivers.size()));
Expand Down Expand Up @@ -303,6 +306,15 @@ private Map<String, Object> seedRepository(String name, DriverSet ds, String mes
throw new TreeService.BadRequest(repo + " exists already; choose 'an existing repository' for it, or another name");
}
Files.createDirectories(repo.getParent());
// what the read left out (two objects of one name: DirXMLDev's DuplicateArtifacts) goes on the
// page and into the first commit, so the person can decide in Designer (#174)
List<String> leftOut = new ArrayList<>();
for (com.pointblue.dirxml.dev.model.DuplicateArtifacts.Dropped d : ds.duplicates) {
leftOut.add(d.note + ". " + d.advice + ".");
}
if (!leftOut.isEmpty()) {
message = message + "\n\n" + String.join("\n", leftOut);
}
Path seed = Files.createTempDirectory("idmweb-seed");
Git git = workspaces.git();
try {
Expand All @@ -326,6 +338,9 @@ private Map<String, Object> seedRepository(String name, DriverSet ds, String mes
m.put("repository", repo.toString());
m.put("tree", "tree");
m.put("drivers", ds.drivers.size());
if (!leftOut.isEmpty()) {
m.put("notes", leftOut);
}
return m;
}

Expand Down
15 changes: 13 additions & 2 deletions web/src/components/SetupView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ export function SetupView({ first, onDone, onConnections, onCancel }: { first: b
fn()
.then((r) => {
setResult(r);
setTimeout(() => onDone(r.project ?? null), 1200);
// notes (what the import left out) stay until the person has read them
if (!r.notes?.length) {
setTimeout(() => onDone(r.project ?? null), 1200);
}
})
.catch((e: Error) => setError(e.message))
.finally(() => setBusy(null));
Expand Down Expand Up @@ -89,7 +92,15 @@ export function SetupView({ first, onDone, onConnections, onCancel }: { first: b
{n}
</p>
))}
<p className="muted">Opening the workbench…</p>
{result.notes?.length ? (
<p>
<button className="primary" onClick={() => onDone(result.project ?? null)}>
Open the workbench
</button>
</p>
) : (
<p className="muted">Opening the workbench…</p>
)}
</div>
);
}
Expand Down
Loading